using FreeTypeSharp;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.PackageManager;
using UnityEngine;
using UnityEngine.XR;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class drawtext_freetype : MonoBehaviour
{
    public TextAsset font;
    public string drawText;


    PackTexture packTexture;
    unsafe FT_LibraryRec_* _ft_lib = null;//ttf library
    unsafe FT_FaceRec_* _ft_face = null;//对应字体的face
    string _text;

    byte[] _ttf;

    List<Vector3> mesh_pos = new List<Vector3>();
    List<Vector2> mesh_uv = new List<Vector2>();
    int mesh_x = 0;
    const int fontsize = 64;
    // Start is called before the first frame update
    void Start()
    {

    }
    //简洁的Glyph转换函数
    //不能显示特殊字符，问题就出在这个函数上
    unsafe uint[] String2Glyphs(string text)
    {
        List<uint> glyphs = new List<uint>();
        foreach (var c in text)
        {
            var index = FT.FT_Get_Char_Index(_ft_face, (System.UIntPtr)c);
            glyphs.Add(index);
            //Debug.LogWarning(c + "=>" + index);
        }
        return glyphs.ToArray();
    }
    // Update is called once per frame
    void Update()
    {
        bool dirty = false;
        if (drawText != _text)
        {

            _text = drawText;
            dirty = true;
            Debug.LogWarning("text dirty");
        }
        if (_ttf == null || font.bytes == null || _ttf.Length != font.bytes.Length)
        {
            _ttf = font.bytes;
            ClearFont();
            dirty = true;
            Debug.LogWarning("font dirty");
        }
        if (dirty)
        {

            UpdateText();
        }

    }

    unsafe void UpdateText()
    {
        ClearMesh();

        if (_ft_lib == null)
        {
            packTexture = new PackTexture();



            FT_LibraryRec_* lib;
            FT.FT_Init_FreeType(&lib);
            _ft_lib = lib;
        }

        if (_ttf == null || _text == null)
        {
            return;
        }

        if (_ft_face == null)
        {
            fixed (byte* ptr = _ttf)
            {
                FT_FaceRec_* face;
                FT.FT_New_Memory_Face(_ft_lib, ptr, (System.IntPtr)_ttf.Length, (System.IntPtr)0, &face);
                FT.FT_Set_Char_Size(face, (System.IntPtr)0, (System.IntPtr)(fontsize << 6), 300, 300);
                _ft_face = face;
            }
        }
        var glyphs = String2Glyphs(_text);

        UpdateMesh(packTexture, glyphs);
    }
    unsafe void ClearFont()
    {
        FT.FT_Done_Face(_ft_face);
        _ft_face = null;
    }
    unsafe void Load_Glyph(uint glyph_index)
    {
        var error = FT.FT_Load_Glyph(_ft_face, glyph_index, FT_LOAD.FT_LOAD_DEFAULT);
        error = FT.FT_Render_Glyph(_ft_face->glyph, FT_Render_Mode_.FT_RENDER_MODE_NORMAL);
    }
    unsafe FT_GlyphSlotRec_* GetGlyph()
    {
        return _ft_face->glyph;
    }
    void ClearMesh()
    {
        this.GetComponent<MeshFilter>().mesh = new Mesh();
    }
    unsafe void UpdateMesh(PackTexture packTexture, uint[] glyphs)
    {
        packTexture.ClearGlyph();

        var mesh = this.GetComponent<MeshFilter>().mesh;
        var mat = this.GetComponent<MeshRenderer>().material;
        mat.mainTexture = packTexture.texture;

        mesh_x = 0;
        mesh_pos.Clear();
        mesh_uv.Clear();
        foreach (var g in glyphs)
        {
            if (packTexture.TryGetGlyph(g, out var info))
            {

            }
            else
            {
                Load_Glyph(g);
                info = packTexture.UpdateGlyph(GetGlyph());
                ;
            }
            UpdateMesh_Char(info);
        }
        mesh.vertices = mesh_pos.ToArray();
        mesh.uv = mesh_uv.ToArray();

        int[] tris = new int[mesh.vertices.Length / 4 * 6];
        for (var i = 0; i < mesh.vertices.Length / 4; i++)
        {
            tris[i * 6 + 0] = i * 4 + 0;
            tris[i * 6 + 1] = i * 4 + 1;
            tris[i * 6 + 2] = i * 4 + 2;
            tris[i * 6 + 3] = i * 4 + 2;
            tris[i * 6 + 4] = i * 4 + 1;
            tris[i * 6 + 5] = i * 4 + 3;
        }
        mesh.triangles = tris;

        Color32[] colors = new Color32[mesh.vertices.Length];
        for (var i = 0; i < colors.Length; i++)
        {
            colors[i] = Color.white;
        }
        mesh.colors32 = colors;

        mesh.SetSubMesh(0, new UnityEngine.Rendering.SubMeshDescriptor(0, tris.Length, MeshTopology.Triangles));
        mesh.UploadMeshData(false);
    }
    void UpdateMesh_Char(CharInfo info)
    {
        var mesh = this.GetComponent<MeshFilter>().mesh;
        float scale = 1.0f/64;
        mesh_pos.Add(new Vector3(scale*(mesh_x + info.border_left),
            scale * (info.border_top), 0));
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left + info.width),
            scale * (info.border_top), 0));
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left),
            scale * (info.border_top - info.height), 0));
        mesh_pos.Add(new Vector3(scale * (mesh_x + info.border_left + info.width),
            scale * (info.border_top - info.height), 0));

        mesh_uv.Add(new Vector3(info.u0, info.v0));
        mesh_uv.Add(new Vector3(info.u1, info.v0));
        mesh_uv.Add(new Vector3(info.u0, info.v1));
        mesh_uv.Add(new Vector3(info.u1, info.v1));



        mesh_x += info.advX;
        //Debug.Log("mesh_x=" + mesh_x);
    }
}
